home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / disk / misc / string11.lha / strings.c < prev    next >
C/C++ Source or Header  |  1992-01-12  |  10KB  |  474 lines

  1. /*
  2.  *  FILE
  3.  *    strings.c
  4.  *
  5.  *  VERSION
  6.  *    V1.02, Not Released
  7.  *
  8.  *  DESCRIPTION
  9.  *    A utility which prints out strings in binary files.
  10.  *
  11.  *    This program can also be seen as a test for my "ALiLib"
  12.  *    project. The program relies on 1) The clop() function for
  13.  *    parsing options and
  14.  *    2) My version of malloc/free is also used. I don't know wheter
  15.  *    or not it differs from the lattice version, but Lattice is
  16.  *    known not to be simple......
  17.  *
  18.  *  STATUS
  19.  *    All rights reserved.
  20.  *
  21.  *  AUTHOR
  22.  *    Anders 'ALi' Lindgren
  23.  *    Mälarblick 8
  24.  *    S-161 51 Bromma
  25.  *    Sweden
  26.  *
  27.  *  CODE HISTORY
  28.  *    Some years ago    Idea
  29.  *    90-Dec-10    Preliminary specs written during some booring
  30.  *            army radio guard night-hours.
  31.  *    90-Dec-16    Start of hacking, Program basically ready.
  32.  *            Several fancy details included, like ctrl-C.
  33.  *    91-Jan-09 V1.01    Skip starting blanks
  34.  *    92-Jan-12 V1.02    View only strings terminated by NIL, CR, LF or
  35.  *            TAB and long strings (which doesn't fit into
  36.  *            the buffer).
  37.  *            Static version string added.
  38.  *
  39.  *  SEE ALSO
  40.  *    ALiLib-documentation
  41.  *    strings.doc
  42.  *
  43.  *  TODO
  44.  *    ALiLib-interfacing.
  45.  *    A 0xFF (ÿ) remover? (option?)
  46.  */
  47.  
  48. static char * version_strings = "\0$VER: strings V1.02 (" __DATE__
  49.                 ") by Anders Lindgren.";
  50.  
  51. #include <exec/types.h>
  52.  
  53. #include <libraries/dos.h>
  54.  
  55. #define _USEOLDEXEC_
  56. #include <proto/exec.h>
  57. #include <proto/dos.h>
  58.  
  59. #include <ctype.h>
  60. #include "stdlib.h"    /* It doesn't hurt if it's my own. */
  61.  
  62. #include "clop.h"
  63.  
  64.  
  65. /*
  66.  *  DEFINITIONS
  67.  */
  68.  
  69. #define BUFSIZE    512    /* Remember, it's stored on the stack */
  70.  
  71.  
  72. /*
  73.  *  WARNING! These definitions corresponds to the clop_array below!
  74.  */
  75.  
  76. #define OPTION_SMALL    0
  77. #define OPTION_EXTENDED    1
  78. #define OPTION_BYTE    2
  79. #define OPTION_OUTPUT    3
  80. #define OPTION_USAGE    4
  81. #define OPTION_HELP    5
  82.  
  83.  
  84. #define DOS_PRINT(x) Write(Output(),(x),sizeof(x))
  85.  
  86. #define tohex(x)    ((x)>9?(x)+'A'-10:(x)+'0')
  87.  
  88.  
  89. /*
  90.  *  DEFINE
  91.  *    isprint()
  92.  *
  93.  *  DESCRIPTION
  94.  *    A simple Amiga-specific isprint(). This is much shorter than
  95.  *    dragging in a _ctype array.
  96.  */
  97.  
  98. #ifdef isprint
  99. #undef isprint
  100. #endif
  101.  
  102. #define isprint(c)    ((((c)>=32) && ((c)<=126)) || (((c)>=160) && ((c)<=255)))
  103.  
  104.  
  105. /*
  106.  *  FORWARD REFERENCES
  107.  */
  108.  
  109. extern int  parse_opts(char *, struct clop_array *);
  110. extern int  aloha(BPTR, BPTR, int, int, int);
  111. extern void write_offset(BPTR, unsigned long);
  112.  
  113.  
  114. /*
  115.  *  GLOBAL VARIABLES
  116.  */
  117.  
  118. struct DosLibrary * DOSBase;
  119.  
  120.  
  121. /*
  122.  *  FUNCTION
  123.  *    not_main
  124.  *
  125.  *  DESCRIPTION
  126.  */
  127.  
  128. int __saveds __asm
  129. not_main(register __a0 char * cline, register __d0 long len)
  130. {
  131.     int       rc;
  132.     char * args;
  133.  
  134.     struct clop_list clop_list = { NULL, '\0' };
  135.  
  136.     struct clop_array clop_array [ ] = {
  137.     { 'n', CLOPT_UNUMBER, 0, 0, 6L   },    /* Shortest string to print */
  138.     { 'e', CLOPT_BOOL,    0, 0, 0L   },    /* Extended character set   */
  139.     { 'b', CLOPT_BOOL,    0, 0, 0L   },    /* Byte offsets            */
  140.     { 'o', CLOPT_STRING,  0, 0, NULL },    /* Output file            */
  141.     { 'u', CLOPT_BOOL,    0, 0, 0L   },
  142.     { '?', CLOPT_BOOL,    0, 0, 0L    },    /* Help page            */
  143.     { '\0', CLOPT_END,    0, 0, NULL }
  144.     };
  145.  
  146.     rc = RETURN_FAIL;
  147.  
  148.     if (DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0L)) {
  149.     cline[len - 1] = '\0';
  150.     if (args = clop(cline, & clop_list, clop_array)) {
  151.  
  152.         if (clop_array[OPTION_HELP].value.bool ||
  153.         clop_array[OPTION_USAGE].value.bool) {
  154.  
  155.         rc = RETURN_OK;
  156.  
  157.         DOS_PRINT(
  158. "Strings V1.01  Written by Anders Lindgren.\n"
  159. "usage: strings [-nX] [-e] [-b] [-ooutfile] [infile]\n"
  160. "    -n Smallest string to print.  (default 6)\n"
  161. "    -e Use extended character set.(default disabled)\n"
  162. "    -b Print out byte offset.     (default disabled)\n"
  163. "    -o Print out to a file insted of standard out.\n" );
  164.  
  165.         }
  166.         else {
  167.         rc = parse_opts( args, clop_array );
  168.         }
  169.  
  170.     }
  171.     else {
  172.         if (clop_list.error == CLOPE_UNKNOWN_OPTION) {
  173.         DOS_PRINT("strings:Unknown switch: -");
  174.         Write(Output(), & clop_list.failing_opt, 1);
  175.         DOS_PRINT("\n");
  176.         }
  177.         else {
  178.         DOS_PRINT("strings:Incorrect usage of switch: -");
  179.         Write(Output(), & clop_list.failing_opt, 1);
  180.         DOS_PRINT("\n");
  181.         }
  182.     }
  183.     /*
  184.      * Free everything allocated.
  185.      */
  186.      
  187.     freeclop(clop_array);
  188.  
  189.     CloseLibrary((struct Library *)DOSBase);
  190.     }
  191.     return (rc);
  192. }
  193.  
  194.  
  195. /*
  196.  *  FUNCTION
  197.  *    parse_opts
  198.  *
  199.  *  DESCRIPTION
  200.  *    Open all files, and establish all flags etc.
  201.  *
  202.  *    Rename function? Guess so....
  203.  */
  204.  
  205. int
  206. parse_opts( char * filename, struct clop_array * clop_array)
  207. {
  208.     BPTR   input;
  209.     BPTR   output;
  210.  
  211.     /* Flags, using opened input/output FH, instead of std* */
  212.     int       closein;
  213.     int    closeout;
  214.  
  215.     unsigned int smallest;
  216.     char * ofn;        /* Output file name    */
  217.     int       rc;        /* Returncode        */
  218.  
  219.     rc = RETURN_FAIL;
  220.  
  221.     smallest = clop_array[OPTION_SMALL].value.unumber;
  222.  
  223.     if ((smallest < BUFSIZE) && (smallest > 0) ) {
  224.  
  225.     /*
  226.      * Establish an input stream.
  227.      */
  228.  
  229.     if (* filename) {
  230.         if (input = Open(filename, MODE_OLDFILE)) {
  231.         closein = TRUE;
  232.         }
  233.         else {
  234.         DOS_PRINT("strings:Didn't find input file.\n");
  235.         return (RETURN_FAIL);
  236.         }
  237.     }
  238.     else {
  239.         input = Input();
  240.         closein = FALSE;
  241.     }
  242.  
  243.     /*
  244.      * Establish output stream.
  245.      */
  246.  
  247.     if (ofn = clop_array[OPTION_OUTPUT].value.string) {
  248.  
  249.         if (* ofn) {
  250.         closeout = TRUE;
  251.         if ( (output = Open(ofn, MODE_NEWFILE)) == NULL) {
  252.             if (closein) {
  253.             Close(input);
  254.             }
  255.             DOS_PRINT("strings:Error opening output file.\n");
  256.             return(RETURN_FAIL);
  257.         }
  258.         }
  259.         else {
  260.         if (closein) {
  261.             Close(input);
  262.         }
  263.         DOS_PRINT("strings:Missing output filename.\n");
  264.         return(RETURN_FAIL);
  265.         }
  266.     }
  267.     else {
  268.         output = Output();
  269.         closeout = FALSE;
  270.     }
  271.  
  272.     /*
  273.      * Call the actual heart of the program, and serv it all
  274.      * it want to know on a silver plate.
  275.      */
  276.  
  277.     rc = aloha(input, output, smallest,
  278.         clop_array[OPTION_EXTENDED].value.bool,
  279.         clop_array[OPTION_BYTE].value.bool);
  280.  
  281.     /*
  282.      * Clean up files
  283.      */
  284.  
  285.     if (closein) {
  286.         Close(input);
  287.     }
  288.  
  289.     if (closeout) {
  290.         Close(output);
  291.     }
  292.     }
  293.     else {
  294.     DOS_PRINT("strings:Illegal -n number.\n");
  295.     }
  296.     return(rc);
  297. }
  298.  
  299.  
  300. /*
  301.  *  FUNCTION
  302.  *    aloha
  303.  *
  304.  *  DESCRIPTION
  305.  *    The actual main loop.
  306.  *
  307.  *    The name? Naw, I really can't think of any good, since
  308.  *    it's only a main, level 3.
  309.  *
  310.  *  SYNOPSIS
  311.  *    aloha(input, output, smallest, extended, byteflg)
  312.  *        input, output - AmigaDOS filehandlers.
  313.  *        smallest      - Shortest length to bother to print
  314.  *        extended      - (flag) Consider the extended characters.
  315.  *        byteflg          - (flag) Print out the byteoffset.
  316.  */
  317.  
  318. int
  319. aloha(BPTR input, BPTR output, int smallest, int extended, int byteflg)
  320. {
  321.     unsigned char inbuf [BUFSIZE];
  322.     unsigned char outbuf[BUFSIZE];
  323.  
  324.     int soffset;
  325.     int doffset = 0;
  326.  
  327.     long counter = 0;
  328.     long byteoffset = 0;
  329.     unsigned char ch;
  330.  
  331.  
  332.     int al;    /* Actual length read */
  333.  
  334.     /* A _very_ long output line, longer than one buffer. */
  335.     int longflg = FALSE;
  336.  
  337.     int ctrlc = FALSE;
  338.  
  339.     do {    /* Until eof, or ctrl-C pressed */
  340.  
  341.     al = Read(input, inbuf, BUFSIZE);
  342.  
  343.         /* Check each character in the input buffer */
  344.     for (soffset = 0; ( (soffset < al) && ! ctrlc ); soffset++) {
  345.  
  346.         ch = inbuf[soffset];
  347.  
  348.         /*
  349.          * Check if the character is printable.
  350.          */
  351.         if ( isprint(ch) && (extended || isascii(ch)) ) {
  352.  
  353.             /*
  354.              * Don't register spaces if they start a string.
  355.              */
  356.         if (ch != ' ' || doffset != 0 || longflg) {
  357.  
  358.             /*
  359.              * Save the position for this string
  360.              */
  361.             if ((doffset == 0) && (! longflg)) {
  362.             byteoffset = counter;
  363.             }
  364.  
  365.             outbuf[doffset++] = ch;
  366.  
  367.             /*
  368.              * Is the output buffer full?
  369.              * Let's empty it and flag.
  370.              */
  371.             if (doffset == BUFSIZE) {
  372.             if ( (! longflg) && (byteflg) ) {
  373.                 write_offset(output, byteoffset);
  374.             }
  375.             Write(output, outbuf, BUFSIZE);
  376.             longflg = TRUE;
  377.             doffset = 0;
  378.             }
  379.         }
  380.         }
  381.         else {
  382.  
  383.         /*
  384.          * A nonprintable character found, let's see
  385.          * if the characters found before if it's long
  386.          * enough to print, or if the characters in
  387.          * the buffer is part of a earlier, very long,
  388.          * string.
  389.          *
  390.          * 1992-01-12:  Just strings which are terminated
  391.          *        by NIL, CR, LF or TAB are considered
  392.          *        strings, if the string aren't so
  393.          *        big so it doesn't fit the buffer,
  394.          *        in which case we will se it anyway.
  395.          */
  396.  
  397.         if ( ( ((ch == '\0') ||
  398.             (ch == 10)  ||
  399.             (ch == 13)  ||
  400.             (ch == 9))    && (doffset >= smallest) ) || 
  401.              longflg ) {
  402.             if ( (! longflg) && (byteflg) ) {
  403.             write_offset(output, byteoffset);
  404.             }
  405.             Write(output, outbuf, doffset);
  406.             Write(output, "\n", 1);
  407.         }
  408.         doffset = 0;
  409.         longflg = FALSE;
  410.         }
  411.         counter++;    /* Byte counter */
  412.  
  413.         if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) {
  414.         ctrlc = TRUE;
  415.         }
  416.     }
  417.     } while((al > 0) && (!ctrlc));
  418.  
  419.     /*
  420.      * If the file ended, and we have a correct strings in our
  421.      * buffer, print it out.
  422.      */
  423.  
  424.     if (ctrlc) {
  425.     DOS_PRINT("*** Break!\n");
  426.     }
  427.     else if ((doffset >= smallest) || longflg) {
  428.     if ( (! longflg) && (byteflg) ) {
  429.         write_offset(output, byteoffset);
  430.     }
  431.     Write(output, outbuf, doffset);
  432.     Write(output, "\n", 1);
  433.     }
  434.  
  435.     return(al >= 0 ? RETURN_OK : RETURN_ERROR);
  436. }
  437.  
  438.  
  439. /*
  440.  *  FUNCTION
  441.  *    write_offset
  442.  *
  443.  *  DESCRIPTION
  444.  *    This function writes out the offset in the form:
  445.  *    "X:" where X are at four or eigth hexadecimal
  446.  *    digits.
  447.  */
  448.  
  449. void
  450. write_offset(BPTR output, unsigned long offset)
  451. {
  452.     char outbuf[9];
  453.  
  454.     int i;
  455.     int firstn0;
  456.  
  457.     outbuf[8] = ':';
  458.  
  459.     /*
  460.      * Decide if we shall print out four hexadecial digits, or
  461.      * if we need all eight.
  462.      */
  463.     firstn0 = offset & 0xFFFF0000 ? 0 : 4;
  464.  
  465.     for (i=7; i>=0; i--) {
  466.     outbuf[i] = tohex(offset & 0x0F);
  467.     offset >>= 4;
  468.     }
  469.  
  470.     Write(output, & outbuf[firstn0], 9-firstn0);
  471.  
  472.     return;
  473. }
  474.